import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { ArrowRight, Brain, Eye, Link2, MessagesSquare, Scissors, Wrench } from "lucide-react"; import { getPublicShare, readShareMeta } from "@/lib/conversations/service"; import { LogoMark, Wordmark } from "@/components/brand/logo"; import { ProviderIcon } from "@/components/brand/provider-icon"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { SimpleMarkdown } from "@/components/markdown/simple-markdown"; import { providerName } from "@/lib/client/providers"; import { formatMs, formatTokens, cn } from "@/lib/utils"; export const dynamic = "force-dynamic"; /* ------------------------------------------------------------------------------------------------ * Snapshot shape (frozen copy written by `shareConversation`). Parsed defensively; the optional first * `$meta` element (v2) is skipped by the message parser and read separately with `readShareMeta`. * ---------------------------------------------------------------------------------------------- */ type SnapPart = | { type: "text"; text: string } | { type: "reasoning"; text: string; durationMs?: number } | { type: "tool-call"; id?: string; name: string; arguments?: Record; argumentsText?: string; result?: unknown; isError?: boolean } | { type: "citation"; url?: string; title?: string; snippet?: string }; interface SnapMessage { role: "user" | "assistant" | "system"; content: string; modelKey: string | null; createdAt: string | null; parts: SnapPart[]; usage: { inputTokens?: number; outputTokens?: number; totalTokens?: number } | null; latencyMs: number | null; } function isRecord(v: unknown): v is Record { return typeof v === "object" && v !== null; } function parseSnapshot(raw: unknown): SnapMessage[] { if (!Array.isArray(raw)) return []; const out: SnapMessage[] = []; for (const m of raw) { if (!isRecord(m)) continue; const role = m.role === "user" || m.role === "assistant" || m.role === "system" ? m.role : null; if (!role) continue; const parts: SnapPart[] = []; if (Array.isArray(m.parts)) { for (const p of m.parts) { if (!isRecord(p) || typeof p.type !== "string") continue; if ((p.type === "text" || p.type === "reasoning") && typeof p.text === "string") parts.push(p as SnapPart); else if (p.type === "tool-call" && typeof p.name === "string") parts.push(p as SnapPart); else if (p.type === "citation") parts.push(p as SnapPart); } } const createdAt = typeof m.createdAt === "string" ? m.createdAt : m.createdAt instanceof Date ? m.createdAt.toISOString() : null; out.push({ role, content: typeof m.content === "string" ? m.content : "", modelKey: typeof m.modelKey === "string" ? m.modelKey : null, createdAt, parts, usage: isRecord(m.usage) ? (m.usage as SnapMessage["usage"]) : null, latencyMs: typeof m.latencyMs === "number" ? m.latencyMs : null, }); } return out; } function splitModelKey(key: string | null): { provider: string | null; model: string | null } { if (!key) return { provider: null, model: null }; const [provider, ...rest] = key.split("/"); return { provider: provider || null, model: rest.join("/") || key }; } function formatDate(d: Date) { return d.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" }); } /* ------------------------------------------------------------------------------------------------ * Metadata — noindex, per-share OG title * ---------------------------------------------------------------------------------------------- */ export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise { const { id } = await params; const share = await getPublicShareSafe(id, { peek: true }); const count = share ? parseSnapshot(share.snapshot).filter((m) => m.role !== "system").length : 0; const description = share ? `A conversation shared from PolyLLM · ${count} message${count === 1 ? "" : "s"}.` : "This shared conversation is unavailable."; return { title: share ? share.title : "Shared conversation", description, robots: { index: false, follow: false, nocache: true, googleBot: { index: false, follow: false } }, openGraph: share ? { title: `${share.title} · Shared from PolyLLM`, description, type: "article", siteName: "PolyLLM" } : undefined, twitter: share ? { card: "summary", title: `${share.title} · Shared from PolyLLM`, description } : undefined, }; } async function getPublicShareSafe(id: string, opts: { peek?: boolean } = {}) { if (!id || id.length > 128 || !/^[\w-]+$/.test(id)) return null; try { return await getPublicShare(id, opts); } catch { return null; } } /* ------------------------------------------------------------------------------------------------ * Page — mobile-first: 16px gutters, stacked header, full-width CTA; widens at sm/md. * ---------------------------------------------------------------------------------------------- */ export default async function SharePage({ params }: { params: Promise<{ id: string }> }) { const { id } = await params; const share = await getPublicShareSafe(id); if (!share) notFound(); const messages = parseSnapshot(share.snapshot).filter((m) => m.role !== "system"); const meta = readShareMeta(share.snapshot); const models = Array.from(new Set(messages.map((m) => m.modelKey).filter((k): k is string => !!k))); const created = share.createdAt instanceof Date ? share.createdAt : new Date(share.createdAt as unknown as string); const views = share.viewCount + 1; // this visit was counted after the row was read return (
· Shared conversation

Shared from PolyLLM {meta?.partial ? ( Excerpt · {meta.selectedCount} of {meta.totalCount} ) : null}

{share.title}

Shared on
·
Messages
{messages.length} message{messages.length === 1 ? "" : "s"}
·
Views
{views} view{views === 1 ? "" : "s"}
{models.length ? (
    {models.map((k) => { const { provider, model } = splitModelKey(k); return (
  • {model}
  • ); })}
) : null}
    {messages.map((m, i) => (
  1. ))}

Frozen snapshot shared by a PolyLLM user · attachments are not included · model output can be wrong.{" "} Privacy {" · "} Terms

); } /* ------------------------------------------------------------------------------------------------ * Message rendering * ---------------------------------------------------------------------------------------------- */ function MessageView({ message }: { message: SnapMessage }) { if (message.role === "user") { const text = message.parts.filter((p): p is Extract => p.type === "text").map((p) => p.text).join("\n\n") || message.content; return (

You said:

{text}
); } const { provider, model } = splitModelKey(message.modelKey); const reasoning = message.parts.filter((p): p is Extract => p.type === "reasoning" && p.text.trim().length > 0); const tools = message.parts.filter((p): p is Extract => p.type === "tool-call"); const citations = message.parts.filter((p): p is Extract => p.type === "citation" && !!p.url); const textParts = message.parts.filter((p): p is Extract => p.type === "text"); const text = textParts.map((p) => p.text).join("\n\n") || message.content; const totalTokens = message.usage?.totalTokens ?? ((message.usage?.inputTokens ?? 0) + (message.usage?.outputTokens ?? 0) || null); return (
{model ?? "Assistant"} {provider ? {providerName(provider)} : null}
{reasoning.length ? (
Reasoning {reasoning[0].durationMs ? · {formatMs(reasoning[0].durationMs)} : null} Show Hide
{reasoning.map((r) => r.text).join("\n\n")}
) : null} {tools.length ? (
    {tools.map((t, i) => (
  • {t.name} {t.isError ? error : null}
    {t.argumentsText || t.arguments ?
    {t.argumentsText ?? JSON.stringify(t.arguments, null, 2)}
    : null}
  • ))}
) : null}
{text ? {text} : "No text in this message."}
{citations.length ? (
    {citations.map((c, i) => (
  1. {c.title || c.url}
  2. ))}
) : null} {totalTokens || message.latencyMs ? (

{totalTokens ? `${formatTokens(totalTokens)} tokens` : null} {totalTokens && message.latencyMs ? " · " : null} {message.latencyMs ? formatMs(message.latencyMs) : null}

) : null}
); }